package top.codedance.iotp.simulator.serialPort;

import top.codedance.iotp.simulator.serialPort.bean.ComConnectParam;
import top.codedance.iotp.simulator.serialPort.listenner.SerialPortListener;
import com.fazecast.jSerialComm.SerialPort;
import org.apache.log4j.Logger;
import org.ini4j.Ini;

public class ComServer implements Runnable {
    private Logger logger = SimulatorApplication.getLogger(ComServer.class);
    private SerialPort mSerialPort = null;
    private ComConnectParam comConnectParam;

    public ComServer() { }

    @Override
    public void run() {
        init();
    }

    private void init(){
        String comName = null;
        boolean useRS485Mode = false;
        int newBaudRate = 9600, newDataBits = 8, newStopBits = 1, newParity = 0;
        if (SimulatorApplication.ini != null && SimulatorApplication.ini.containsKey("com")) {
            Ini.Section section = SimulatorApplication.ini.get("com");
            if (section.containsKey("comName")) {
                comName = section.get("comName");
            }
            if (section.containsKey("newBaudRate")) {
                newBaudRate = Integer.parseInt(section.get("newBaudRate"));
            }
            if (section.containsKey("newDataBits")) {
                newDataBits = Integer.parseInt(section.get("newDataBits"));
            }
            if (section.containsKey("newStopBits")) {
                newStopBits = Integer.parseInt(section.get("newStopBits"));
            }
            if (section.containsKey("newParity")) {
                newParity = Integer.parseInt(section.get("newParity"));
            }
            if (section.containsKey("useRS485Mode")) {
                useRS485Mode = Boolean.parseBoolean(section.get("useRS485Mode"));
            }
            comConnectParam = new ComConnectParam(comName, newBaudRate, newDataBits, newStopBits, newParity, useRS485Mode);

            try {
                connect();
            }catch (Exception ex){
                logger.info(ex.getMessage());
                System.exit(0);
            }
            long time = System.currentTimeMillis();
            while (true) {
                if (mSerialPort == null || !mSerialPort.isOpen()) {
                    try {
                        connect();
                    }catch (Exception ex){
                        logger.info(ex.getMessage());
                    }
                    logger.info("Com[" + comName + "] sever is reconnect!");
                }else{
                    if(System.currentTimeMillis() - time > 1000 * 3600 * 2){
                        close();
                        try {
                            connect();
                        }catch (Exception ex){
                            logger.info(ex.getMessage());
                        }
                        time = System.currentTimeMillis();
                    }
                }
                try {
                    Thread.sleep(3000);
                } catch (Exception ex) { }
            }
        }else{
            logger.info("Not found com config.");
        }
    }

    private void connect() throws Exception {
        if(comConnectParam != null) {
            SerialPort[] ports = SerialPort.getCommPorts();
            if (ports.length == 0) {
                return;
            }
            int portToUse = -1;
            for (int i = 0; i < ports.length; ++i) {
                String systemPortName = ports[i].getSystemPortName();
                if (systemPortName.contains(comConnectParam.getComName())) {
                    portToUse = i;
                    break;
                }
            }
            if (portToUse < 0) {
                throw new Exception("Not found com.");
            }
            mSerialPort = ports[portToUse];
            mSerialPort.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED);
            mSerialPort.setComPortParameters(comConnectParam.getNewBaudRate(), comConnectParam.getNewDataBits(), comConnectParam.getNewStopBits(), comConnectParam.getNewParity(), comConnectParam.isUseRS485Mode());
            mSerialPort.addDataListener(new SerialPortListener(this));
            if (!mSerialPort.openPort(0, 1024 * 1024 * 2, 1024 * 1024 * 2)) {
                mSerialPort = null;
            }
            logger.info("Com server is running!");
        }else{
            logger.info("Com must have params.");
        }
    }

    public boolean isOpen(){
        return mSerialPort.isOpen();
    }

    public void close(){
        if(mSerialPort != null && mSerialPort.isOpen()) {
            mSerialPort.closePort();
        }
    }
}
